package org.mics.cyy.backUser.service.impl;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import javax.annotation.Resource;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import javax.transaction.Transactional;

import org.apache.commons.lang3.StringUtils;
import org.mics.cache.redis.RedisHelper;
import org.mics.core.context.ServletContextHolder;
import org.mics.core.page.PageInfo;
import org.mics.core.page.PageQuery;
import org.mics.core.response.PageDataResponse;
import org.mics.cyy.backUser.entity.BackUserDO;
import org.mics.cyy.backUser.enums.BackUserEnum;
import org.mics.cyy.backUser.exception.BackUserException;
import org.mics.cyy.backUser.repository.BackUserRepository;
import org.mics.cyy.backUser.request.BackUserRequest;
import org.mics.cyy.backUser.request.EditUserPassRequest;
import org.mics.cyy.backUser.request.LoginRequest;
import org.mics.cyy.backUser.service.BackUserService;
import org.mics.cyy.backUser.service.LoginLogService;
import org.mics.cyy.backUser.vo.BackUserTokenVO;
import org.mics.cyy.backUser.vo.BackUserVO;
import org.mics.lang.bean.BeanConvertUtil;
import org.mics.lang.exception.CustomException;
import org.mics.lang.net.IpUtils;
import org.mics.lang.security.PasswordUtil;
import org.mics.token.enums.TokenEnum;
import org.mics.token.jwt.JwtPayLoad;
import org.mics.token.service.TokenService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;

/**
 * 终端用户
 * @author mics
 * @date 2020年6月10日
 * @version  1.0
 */
@Service
public class BackUserServiceImpl implements BackUserService {
	@Resource
	private BackUserRepository backUserRepository;
	@Resource
	private TokenService tokenService;
	@Resource
	private LoginLogService loginLogService;
	@Resource
	private RedisHelper redisHelper;
	private static final Logger LOGGER = LoggerFactory.getLogger(BackUserServiceImpl.class);
	
	
	
	@Override
	@Transactional
	public BackUserTokenVO login(LoginRequest loginRequest) {
		LOGGER.debug("账号密码登录[loginRequest:{}]", loginRequest);
        //query
        BackUserDO backUserDO = backUserRepository.findByAccount(loginRequest.getAccount());
        //未注册
        if (backUserDO == null) {
            LOGGER.info("账号密码登录失败，该账号未注册[loginAccount:{}]", loginRequest.getAccount());
            throw new BackUserException("该账号未注册");
        }
        //已失效
        if (backUserDO.getStatus() != BackUserEnum.Status.ACTIVE) {
            LOGGER.info("手机号验证码登录失败，该账号已失效[loginAccount:{}]", loginRequest.getAccount());
            throw new BackUserException("该账号已失效");
        }
        //用户名或密码错误
        if (!PasswordUtil.validatePassword(loginRequest.getPassword(), backUserDO.getLoginPasswordSalt(), backUserDO.getLoginPassword())) {
            LOGGER.info("账号密码登录失败，用户名或密码错误[loginAccount:{}]", loginRequest.getAccount());
            throw new BackUserException("用户名或密码错误");
        }
        //vo
		//登录日志
		loginLogService.save(backUserDO.getId(), new Date(), IpUtils.getIpAddr(ServletContextHolder.getHttpServletRequest()));
        //生成token
        String token = createToken(backUserDO);
        //vo
        BackUserTokenVO backUserTokenVO = new BackUserTokenVO();
        backUserTokenVO.setToken(token);
        backUserTokenVO.setAccount(loginRequest.getAccount());
        backUserTokenVO.setNickName(backUserDO.getNickName());
        backUserTokenVO.setRoleId(backUserDO.getRoleId());
        backUserTokenVO.setId(backUserDO.getId());
        LOGGER.info("账号密码登录成功");
        //存储登录信息
        redisHelper.set(token, backUserDO.getId(), 3600);
        return backUserTokenVO;
	}
	
	

	private String createToken(BackUserDO endUserDO) {
		LOGGER.debug("开始为用户生成token[endUserId:{}]", endUserDO.getId());
		//生成token
		JwtPayLoad jwtPayLoad = new JwtPayLoad(endUserDO.getId(), endUserDO.getAccount(), TokenEnum.TokenSource.END_USER);
		String token = tokenService.generate(jwtPayLoad);
		
		LOGGER.info("为用户生成token成功");
		return token;
	}

	/**
	 * 分页获取用户列表
	 * 2020年7月1日
	 */
	@Override
	public PageDataResponse<BackUserVO> listByPage(PageQuery pageQuery){
		//规格定义
        Specification<BackUserDO> specification = new Specification<BackUserDO>() {
			private static final long serialVersionUID = -8785309034575411806L;
			/**
             * 构造断言
             * @param root 实体对象引用
             * @param query 规则查询对象
             * @param cb 规则构建对象
             * @return 断言
             */
            @Override
            public Predicate toPredicate(Root<BackUserDO> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
            	List<Predicate> lstPredicates = new ArrayList<Predicate>();
				Predicate[] arrayPredicates = new Predicate[lstPredicates.size()];
				lstPredicates.add(cb.equal(root.get("flag").as(String.class),2));
				if(StringUtils.isNotBlank(pageQuery.getKey())) {
					lstPredicates.add(cb.like(root.get("nickName").as(String.class),"%"+pageQuery.getKey()+"%"));
				}
				return cb.and(lstPredicates.toArray(arrayPredicates));
            }
        };
        
       Pageable pageable = PageRequest.of(pageQuery.getPageIndex()-1>0?pageQuery.getPageIndex():0,pageQuery.getPageSize(),Sort.Direction.DESC, "createDate");
        //查询
       Page<BackUserDO> page = this.backUserRepository.findAll(specification,pageable);
       PageInfo pageInfo = new PageInfo();
       pageInfo.setPageNo(page.getNumber());
       pageInfo.setPageSize(page.getSize());
       pageInfo.setTotalCount(page.getTotalElements());
       pageInfo.setTotalPage(page.getTotalPages());
       List<BackUserVO> pageList = BeanConvertUtil.convertList(page.getContent(), BackUserVO.class);
      return new PageDataResponse<>(pageInfo,pageList);
	}

	@Override
	@Transactional
	public void deleteById(String id) {
		//删除用户
		backUserRepository.deleteById(id);
	}


	@Override
	@Transactional
	public String save(BackUserRequest backUserRequest) {
		//验证账号是否存在
		BackUserDO backUserDO = backUserRepository.findByAccount(backUserRequest.getAccount());
		if(backUserDO != null) {
			throw new CustomException("已经存在账号["+backUserDO.getAccount()+"]");
		}
		backUserDO =  BackUserDO.empty();
		backUserDO.setAccount(backUserRequest.getAccount());
		backUserDO.setNickName(backUserRequest.getNickName());
		backUserDO.setFlag(backUserRequest.getFlag());
		backUserDO.setLoginPassword(PasswordUtil.encryptPassword(backUserRequest.getPassword(), backUserDO.getLoginPasswordSalt()));
		backUserDO.setStatus(BackUserEnum.Status.ACTIVE);
		backUserRepository.save(backUserDO);
		return backUserDO.getId();
	}



	@Override
	@Transactional
	public String editPass(EditUserPassRequest editUserPassRequest) {
		BackUserDO backUserDO = backUserRepository.getById(editUserPassRequest.getUserId());
		backUserDO.setLoginPassword(PasswordUtil.encryptPassword(editUserPassRequest.getNewPass(), backUserDO.getLoginPasswordSalt()));
		backUserRepository.save(backUserDO);
		return backUserDO.getId();
	}



	@Override
	public BackUserDO info(String id) {
		BackUserDO backUserDO = backUserRepository.getById(id);
		return backUserDO;
	}

}
